/*
 * CustomMenu.cpp
 *
 *  Created on: 04.05.2009
 *      Author: h3llfire
 */

#include "CustomMenu.h"
#include <algorithm>
#include <wx/log.h>
#include "../../core/Impp.h"
#include "Icons.h"

namespace Impp {


/*
 * CustomMenuEntry:
 */

	
CustomMenuEntry::CustomMenuEntry(CustomMenuEntryType type, const wxString & moduleName, const wxString & actionName, const wxString & title, const wxString & help, const int defaultOrder,const bool isChecked) :
	type(type),
	moduleName(moduleName),
	actionName(actionName),
	title(title),
	help(help),
	defaultOrder(defaultOrder),
	checked(isChecked),
	itemId(-10){

}

CustomMenuEntry::~CustomMenuEntry()
{
}

CustomMenuEntryType CustomMenuEntry::getType() const
{
	return type;
}
wxString CustomMenuEntry::getModuleName() const
{
	return moduleName;
}
wxString CustomMenuEntry::getActionName() const{
	return actionName;
}
wxString CustomMenuEntry::getTitle() const
{
	return title;
}
wxString CustomMenuEntry::getHelpString() const
{
	return help;
}
int CustomMenuEntry::getDefaultOrder() const
{
	return defaultOrder;
}
bool CustomMenuEntry::isChecked() const
{
	return checked;
}

int CustomMenuEntry::getItemId() const{
	return itemId;
}
void CustomMenuEntry::setItemId(int id){
	this->itemId=id;
}

/*
 * CustomSubMenuEntry
 */

CustomSubmenuEntry::CustomSubmenuEntry(CustomSubMenu* menu, const wxString & moduleName, const wxString & actionName, const wxString & title, const wxString & help, const int defaultOrder) :
	CustomMenuEntry(CUSTOM_MENU_ENTRY_SUBMENU, moduleName,actionName, title, help, defaultOrder),
	menu(menu){
}

CustomSubmenuEntry::~CustomSubmenuEntry()
{
	delete menu;
}

std::vector<CustomMenuEntry*> CustomSubmenuEntry::getEntries(){
	return menu->entries;
}


/*
 * CustomSubMenu
 *
 */

CustomSubMenu::CustomSubMenu(CustomMenu* base) :
	base(base)
{

}
CustomSubMenu::~CustomSubMenu(){
	std::vector<CustomMenuEntry*>::iterator e;
	for(e = entries.begin(); e != entries.end(); e++){
		delete *e;
	}
}


void CustomSubMenu::appendItem(const wxString & actionName, const wxString & item, const int & defaultOrder, const wxString & helpString)
{
	if(base->curInvokedBuilder != NULL){
		entries.push_back(new CustomMenuEntry(CUSTOM_MENU_ENTRY_NORMAL,base->curInvokedBuilder->getModuleName(), actionName, item ,helpString,defaultOrder));
	}else{
		wxLogError(wxT("CustomSubMenu::appendItem: This Method should only be called from an builder!"));
	}

}
void CustomSubMenu::appendCheckItem(const wxString & actionName, const wxString & item,const bool checked, const int & defaultOrder, const wxString & helpString)
{
	if(base->curInvokedBuilder != NULL){
		entries.push_back(new CustomMenuEntry(CUSTOM_MENU_ENTRY_CHECK,base->curInvokedBuilder->getModuleName(), actionName, item, helpString, defaultOrder , checked));
	}else{
		wxLogError(wxT("CustomSubMenu::appendCheckItem: This Method should only be called from an builder!"));
	}
}

iMenu* CustomSubMenu::appendOrGetSubMenu(const wxString & actionName, const wxString & item, const int & defaultOrder, const wxString & helpString){
	if(base->curInvokedBuilder != NULL){
		CustomSubMenu* sub = new CustomSubMenu(base);
		entries.push_back(new CustomSubmenuEntry(sub,base->curInvokedBuilder->getModuleName(), actionName, item, helpString, defaultOrder));
		return sub;
	}else{
		wxLogError(wxT("CustomSubMenu::appendOrGetSubMenu: This Method should only be called from an builder!"));
	}
	return NULL;
}
/*
 *
 * CustomMenuBuilder
 */

CustomMenuBuilder::CustomMenuBuilder(const wxString & moduleName, addMenuItemCallback callback) :
	moduleName(moduleName),
	callback(callback)
{
}

wxString CustomMenuBuilder::getModuleName() const
{
	return moduleName;
}

void CustomMenuBuilder::callAddMenuItemCallback(iMenu* menu, void* userData)
{
	callback(menu, userData);
}
/*
 * CustomMenuEvtHandler
 */


CustomMenuEvtHandler::CustomMenuEvtHandler(CustomMenu* menu) :
	menu(menu)
{

}

void CustomMenuEvtHandler::onMenuItem(wxCommandEvent & event){
	menu->onMenuItem(event);
}
/*
 * Custom Menu
 */

CustomMenu::CustomMenu() :
	evtHandler(this),
	curInvokedBuilder(NULL),
	userData(NULL){}


CustomMenu::~CustomMenu() {
	std::vector<CustomMenuBuilder*>::iterator b;
	for(b = builder.begin(); b != builder.end(); b++){
		delete *b;
	}
	std::vector<CustomMenuEntry*>::iterator e;
	for(e = entries.begin(); e != entries.end(); e++){
		delete *e;
	}
}

void CustomMenu::reigsterMenuEntryAdder(const wxString & moduleName, addMenuItemCallback callback){
	builder.push_back(new CustomMenuBuilder(moduleName, callback));
}

void CustomMenu::appendItem(const wxString & actionName, const wxString & item, const int & defaultOrder, const wxString & helpString)
{
	if(curInvokedBuilder != NULL){
		entries.push_back(new CustomMenuEntry(CUSTOM_MENU_ENTRY_NORMAL,curInvokedBuilder->getModuleName(), actionName, item ,helpString,defaultOrder));
	}else{
		wxLogError(wxT("CustomMenu::appendItem: This Method should only be called from an builder!"));
	}

}
void CustomMenu::appendCheckItem(const wxString & actionName, const wxString & item,const bool checked, const int & defaultOrder, const wxString & helpString)
{
	if(curInvokedBuilder != NULL){
		entries.push_back(new CustomMenuEntry(CUSTOM_MENU_ENTRY_CHECK,curInvokedBuilder->getModuleName(), actionName, item, helpString, defaultOrder , checked));
	}else{
		wxLogError(wxT("CustomMenu::appendCheckItem: This Method should only be called from an builder!"));
	}
}

iMenu* CustomMenu::appendOrGetSubMenu(const wxString & actionName, const wxString & item, const int & defaultOrder, const wxString & helpString){
	if(curInvokedBuilder != NULL){
		CustomSubMenu* sub = new CustomSubMenu(this);
		entries.push_back(new CustomSubmenuEntry(sub,curInvokedBuilder->getModuleName(), actionName, item, helpString, defaultOrder));
		return sub;
	}else{
		wxLogError(wxT("CustomMenu::appendOrGetSubMenu: This Method should only be called from an builder!"));
	}
	return NULL;
}

void CustomMenu::buildMenu(wxMenu* menu, void* userData, int firstId){
	//clear last entries:

	std::vector<CustomMenuEntry*>::iterator e;
	for(e = entries.begin(); e != entries.end();){
		CustomMenuEntry* entry = *e;
		delete entry;
		e = entries.erase(e);
	}

	//Invoke all builders
	std::vector<CustomMenuBuilder*>::iterator b;
	for(b = builder.begin(); b != builder.end(); b++){
		curInvokedBuilder = *b;
		curInvokedBuilder->callAddMenuItemCallback(this, userData);
	}
	curInvokedBuilder = NULL;
	//All Items gettet, so sort them
	std::sort(entries.begin(),entries.end(),CustomMenu::cmp);
	//now for every item, add it to the real menu
	int id = firstId;
	for(e = entries.begin(); e != entries.end(); e++){
		buildEntry(*e,menu,id);
	}
	this->userData=userData;
	menu->SetNextHandler(&evtHandler);
	menu->Connect(wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler(CustomMenuEvtHandler::onMenuItem),NULL, &evtHandler);
}

void CustomMenu::buildEntry(CustomMenuEntry* entry, wxMenu* menu, int & id){
		iIcons* icons = Impp::exemplar()->getModuleManager()->getUserInterfaceModule()->getIcons();


		switch(entry->getType()){
		case CUSTOM_MENU_ENTRY_NORMAL:
			{
				wxMenuItem* item = new wxMenuItem(menu, id,entry->getTitle(),entry->getHelpString(), wxITEM_NORMAL);
				item->SetBitmap(icons->getActionIcon(entry->getModuleName(), entry->getActionName()));
				menu->Append(item);
			}
			break;
		case CUSTOM_MENU_ENTRY_CHECK:
			{
				wxMenuItem* item = new wxMenuItem(menu, id,entry->getTitle(),entry->getHelpString(), wxITEM_CHECK);
				item->SetBitmap(icons->getActionIcon(entry->getModuleName(), entry->getActionName()));
				menu->Append(item);
				menu->Check(id, entry->isChecked());
			}

			break;
		case CUSTOM_MENU_ENTRY_SUBMENU:
			{

				wxMenu* sub = new wxMenu();
				wxMenuItem* item = new wxMenuItem(menu, id,entry->getTitle(),entry->getHelpString(), wxITEM_NORMAL, sub);
				item->SetBitmap(icons->getActionIcon(entry->getModuleName(), entry->getActionName()));
				menu->Append(item);

				CustomSubmenuEntry* m = static_cast<CustomSubmenuEntry*>(entry);

				std::vector<CustomMenuEntry*> entries = m->getEntries();
				std::sort(entries.begin(),entries.end(),CustomMenu::cmp);


				std::vector<CustomMenuEntry*>::iterator e;
				for(e = entries.begin(); e != entries.end(); e++){
					buildEntry(*e,sub,id);
				}

				sub->SetNextHandler(menu);
			}
		}
		entry->setItemId(id);
		id++;
}

void CustomMenu::SetNextHandler(wxEvtHandler* handler){
	evtHandler.SetNextHandler(handler);
}

void CustomMenu::onMenuItem(wxCommandEvent & event)
{

	std::vector<CustomMenuEntry*>::iterator e;
	for(e = entries.begin(); e != entries.end(); e++){
		CustomMenuEntry* entry = *e;
		if(checkEntry(entry, event)){
			return;
		}
	}
	event.Skip();
}

bool CustomMenu::checkEntry(CustomMenuEntry* entry, wxCommandEvent & event){
	if(entry->getType()!=CUSTOM_MENU_ENTRY_SUBMENU){
		if(entry->getItemId() == event.GetId()){

			//something better..
			Buddy* buddy = static_cast<Buddy*>(userData);
			Group* group = static_cast<Group*>(userData);


			Impp::exemplar()->processCommandAction(entry->getModuleName(),entry->getActionName(), event.IsChecked(), buddy, group);
			return true;
		}
	}else{

		std::vector<CustomMenuEntry*> entries = static_cast<CustomSubmenuEntry*>(entry)->getEntries();
		std::vector<CustomMenuEntry*>::iterator e;
		for(e = entries.begin(); e != entries.end(); e++){
			CustomMenuEntry* entry = *e;
			if(checkEntry(entry, event)){
				return true;
			}
		}

	}
	return false;
}

bool CustomMenu::cmp(CustomMenuEntry* a, CustomMenuEntry* b){
	return a->getDefaultOrder() < b->getDefaultOrder();
}

}
